package com.deer.wms.ware.task.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.deer.wms.base.system.model.*;
import com.deer.wms.base.system.service.ErpService;
import com.deer.wms.project.root.core.result.CommonCode;
import com.deer.wms.project.root.exception.ServiceException;
import com.deer.wms.project.root.util.DateUtils;
import com.deer.wms.project.root.util.HttpClient;
import com.deer.wms.project.root.util.RedisUtil;
import com.deer.wms.system.manage.model.DataDictDetail;
import com.deer.wms.ware.task.erp.UpdatePPF;
import com.deer.wms.ware.task.service.ErpPushLogService;
import com.deer.wms.ware.task.service.PushErpService;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * @Author: xu
 * @Date: 2022/05/28/17:51
 * @Description:
 */
@Service
@Slf4j
public class PushErpServiceImpl implements PushErpService {
    @Autowired
    private RedisUtil redisUtil;

        private static final String BaseUrl = "https://61.177.200.186:44391";  //测试账套
        //private static final String BaseUrl = "http://10.18.3.19:34399";  //正式
    @Value("${erp.tokenUrl}")
    private String tokenUrl;

    @Value("${erp.ClientID}")
    private String clientID;
    @Value("${erp.ClientSecret}")
    private String ClientSecret;


    private static final Map<String, String> urlMap = new HashMap<String, String>() {

        {



            put("pullAsn", BaseUrl + "/api/Epichust/GetAllIMInSourceBills");//获取入库数据
            put("pushIMBIll", BaseUrl + "/api/IMBill/PushIMBill");// 出入库回传
            put("create", BaseUrl + "/api/QCBill/PushQCBill");//下推来料检验单，来料检验申请单
            put("createIMBill", BaseUrl + "/api/IMBill/CreateIMBill");//手动建单子回传
            put("pullSo", BaseUrl + "/api/Epichust/GetAllIMOutSourceBills");//出库数据源
            put("sDPackingDelivery", BaseUrl + "/api/SDPackingDelivery/GetSDPackingDeliveriesByAgreementNo/");//出库数据源
            put("SDPacking", BaseUrl + "/api/SDPacking/CreateSDPackingProcessTracking");
            put("CheckBill", BaseUrl + "/api/Bill/CheckBill");
            put("exception", BaseUrl + "/api/QCRawMaterialQualityAbnormal/CreateQCRawMaterialQualityAbnormalIfNotExist"); //移仓单
            put("special", BaseUrl + "/api/QCRawMaterialConcessionAccept/CreateQCRawMaterialConcessionAcceptIfNotExist");//特采单
            put("inventory", BaseUrl + "/api/Epichust/GetIMInventories/");//查询库存
            put("GetPOReceiving", BaseUrl + "/api/Epichust/GetPOReceiving");//查询库存
            put("UpdatePPFeedAssignedQty", BaseUrl + "/api/Epichust/UpdatePPFeedAssignedQty");//更新生产/委外加工投料单已分配数量
            put("PushPOReceivingReturn", BaseUrl + "/api/POReceiving/PushPOReceivingReturn");//来料检验单，退料通知单
            put("GetAllIMSourceBills", BaseUrl + "/api/Epichust/GetAllIMSourceBills");//出入库数据源

        }
    };


    @Autowired
    private ErpService erpService;
    @Autowired
    private ErpPushLogService erpPushLogService;

    /**
     * 下推创建新出入库单：
     * 72-收料通知单 ==> 1-外购入库单；
     * 702-来料检验申请单 ==> 1-外购入库单；
     * 702-来料检验申请单 ==> 5-委外加工产品入库单；
     * 85-生产任务单 ==> 2-产品入库单；
     * 88-生产投料单 ==> 24-生产领料单；
     * 88-委外投料单 ==> 28-委外加工出库单；
     * 83-发货通知单 ==> 41-调拨单；
     * 82-退货通知单 ==> 21-销售出库单；
     * 251300021-生产投料单 ==> 24-生产领料单；
     * 251300021-生产投料单 ==> 29-其他出库单；
     * 251300022-生产退料单 ==> 24-生产领料单；
     * 251300022-生产退料单 ==> 29-其他出库单；
     * 251300056-返修拆改通知单 ==> 10-其他入库单；
     * 251300056-返修拆改通知单 ==> 29-其他出库单；
     * 251300057-返修拆改投料单 ==> 29-其他出库单；
     * 251300058-返修拆改退料单 ==> 29-其他出库单；
     * 200000011-其他出库申请单 ==> 29-其他出库单；
     * 200000013-其他出库(红字退库)申请单 ==> 29-其他出库单
     *
     * @param bean
     */
    @Override
    public Map<String, String> pushIMBIll(OrderToErpBO bean) {
        Map<String, String> pushIMBIll = pushErpUrl(urlMap.get("pushIMBIll"), bean);
//        erpPushLogService.inserBill(bean, pushIMBIll);
        return pushIMBIll;
    }





    /**
     * 质检回传接口
     *
     * @param bean
     */
    @Override
    public String pushQCBIll(QcOrderToErpBO bean) {
        return pushErpUrl(urlMap.get("create"), bean).get("msg");
    }

    @Override
    public String PushPOReceivingReturn(QcOrderToErpBO bean) {
        return pushErpUrl(urlMap.get("PushPOReceivingReturn"), bean).get("msg");
    }


    /**
     * 获取入库数据源
     *
     * @param map@return
     */
    @Override
    public List<PurchaseOrderBO> GetAllIMInSourceBills(Map<String, Object> map) {
//        Map<String, String> map = new HashMap<>();
//        map.put("dateFrom", date);
        String content = pushErpUrl(urlMap.get("GetAllIMSourceBills"), map).get("msg");
        return (List<PurchaseOrderBO>) JSON
                .parseArray(content, PurchaseOrderBO.class);
    }


    /**
     * 获取出库入库数据源
     * @param map
     * @return
     */
    public List<PurchaseOrderBO> GetAllIMSourceBills(Map<String, Object> map) {
        String content = pushErpUrl(urlMap.get("GetAllIMSourceBills"), map).get("msg");
        return (List<PurchaseOrderBO>) JSON
                .parseArray(content, PurchaseOrderBO.class);
    }
    /**
     * 出库数据源
     *
     * @param map
     * @return
     */
    @Override
    public List<BillOutBO> OutSourceBill(Map<String, Object> map) {

        String content = pushErpUrl(urlMap.get("pullSo"), map).get("msg");
        return (List<BillOutBO>) JSON
                .parseArray(content, BillOutBO.class);
    }

    /**
     * 创建新入库单
     */
    @Override
    public Map<String, String> CreateIMBill(OrderToErpBO bean) {

        Map<String, String> map = pushErpUrl(urlMap.get("createIMBill"), bean);
//        if (!map.get("code").equals("200")) {
//            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, map.get("msg"));
//        }
        return map;
    }

    @Override
    public PackingDeliveryBo sDPackingDelivery(String agreementNo) {

        return JSON.parseArray(restFull(urlMap.get("sDPackingDelivery") + agreementNo), PackingDeliveryBo.class).get(0);

    }

    /**
     * 二次回传
     *
     * @param bean
     */
    @Override
    public Map<String, String> twiceSend(OrderToErpBO bean) {
        Map<String, String> pushIMBIll = pushErpUrl(urlMap.get("pushIMBIll"), bean);
        return pushIMBIll;
    }

    /**
     * 251300045-总箱件清单 数据回传
     *
     * @param sdPackingBo
     */
    @Override
    public Map<String, String> sDPacking(SDPackingBo sdPackingBo) {
        Map<String, String> sDPacking = pushErpUrl(urlMap.get("SDPacking"), sdPackingBo);
        if (!sDPacking.get("code").equals("200")) {
            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, sDPacking.get("msg"));
        }
        return sDPacking;
    }

    /**
     * 质检审核
     *
     * @param map
     */
    @Override
    public String CheckBill(Map<String, Object> map) {

        Map<String, String> sDPacking = pushErpUrl(urlMap.get("CheckBill"), map);

        return sDPacking.get("msg");
    }

    /**
     * 获取异常id
     *
     * @param abnormalBillNo
     * @return
     */
    @Override
    public Integer findException(String abnormalBillNo) {
        Map<String, Object> map = new HashMap<>();
        map.put("number", abnormalBillNo);
        Map<String, String> push = pushErpUrl(urlMap.get("exception"), map);
//        if (!push.get("code").equals("200")) {
//            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, push.get("msg"));
//        }
        return Integer.valueOf(push.get("msg"));
    }

    /**
     * 获取特采单号id
     *
     * @param abnormalBillNo
     * @return
     */
    @Override
    public Integer findSpecial(String abnormalBillNo) {
        Map<String, Object> map = new HashMap<>();
        map.put("number", abnormalBillNo);
        Map<String, String> push = pushErpUrl(urlMap.get("special"), map);
//        if (!push.get("code").equals("200")) {
//            throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, push.get("msg"));
//        }
        return Integer.valueOf(push.get("msg"));
    }


    @Override


    public List<Integer> getNotAasnStock() {
        List<Integer> list = new ArrayList<>();

        return list;
    }

    /**
     * 获取入库数据源
     *
     * @param map
     * @return
     */
    @Override
    public PurchaseOrderBO erpByBillNo(Map<String, Object> map) {
        String content = pushErpUrl(urlMap.get("GetPOReceiving"), map).get("msg");
        System.out.println(content);

        return (PurchaseOrderBO) JSON
                .parseObject(content,PurchaseOrderBO.class);
    }

    /**
     * 冻结任务单数量
     * @param list
     */
    @Override
    public void UpdatePPFeedAssignedQty(List<UpdatePPF> list) {
        log.info("回传参数{}", JSON.toJSONString(list));
        pushErpUrl(urlMap.get("UpdatePPFeedAssignedQty"), list).get("msg");
    }

    /**
     * @param url 统一回传接口
     * @param obj
     * @return
     */
    public Map<String, String> pushErpUrl(String url, Object obj) {
        System.out.println(url);

        Map<String, String> repMap = new HashMap<>();
        ErpBackRecord erpRecord = new ErpBackRecord();
        erpRecord.setParam(JSON.toJSONString(obj));
        System.out.println(JSON.toJSONString(obj));
        String token = this.getToken();
        StringEntity myEntity = new StringEntity(JSON.toJSONString(obj), "UTF-8");// 构造请求数据
        //调用erp接口获取数据
        CloseableHttpClient client = HttpClients.createDefault();
        URIBuilder uriBuilder = null;
        try {
            erpRecord.setRequestTime(DateUtils.getNowDateTimeString());
            uriBuilder = new URIBuilder(url);
            HttpPost post = new HttpPost(uriBuilder.build());
            post.setHeader("Content-Type", "application/json");
            post.addHeader("Authorization", "Bearer " + token);
            post.setEntity(myEntity);// 设置请求体
            String responseContent = null; // 响应内容
            CloseableHttpResponse response = null;
            response = client.execute(post);
            HttpEntity entity = response.getEntity();
            InputStream content = entity.getContent();
            String msg = inputStream2String(content);
            System.out.println(msg);
            repMap.put("code", String.valueOf(response.getStatusLine().getStatusCode()));
            repMap.put("msg", msg);
            System.out.println(msg);
            Map<String,String> map = getType(url,msg,obj);
            if (map.get("type") != null){
                erpRecord.setType(map.get("type"));
            }
            if (map.get("return") != null){
                erpRecord.setMsg(map.get("return"));
            }
            if (response.getStatusLine().getStatusCode() == 200) {
                erpRecord.setCode("200");
                erpRecord.setState(2);
                return repMap;
            } else {
                erpRecord.setCode(String.valueOf(response.getStatusLine().getStatusCode()));
                erpRecord.setState(1);
                //   erpRecord.setMsg(msg);
                throw  new ServiceException(CommonCode.SERVER_INERNAL_ERROR,msg);
            }
        } catch (URISyntaxException e) {
            redisUtil.remove(ERP_TOKEN);
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            redisUtil.remove(ERP_TOKEN);
            e.printStackTrace();
        } catch (IOException e) {
            redisUtil.remove(ERP_TOKEN);
            e.printStackTrace();
        } finally {
            try {
                if (erpRecord.getType() != null){
                    erpRecord.setReturnTime(DateUtils.getNowDateTimeString());
                    erpService.saveErpBack(erpRecord);
                }
            } catch (Exception e) {
                log.info("回传ERP异常{}" ,erpRecord.toString());
            }
        }
        return null;
    }

    private Map<String,String> getType(String url,String msg,Object obj){
        Map<String,String> map = new HashMap<>();
        //  JSONObject json = (JSONObject) JSONObject.toJSON(entity);
        if ((BaseUrl+"/api/IMBill/PushIMBill").equals(url)){//出入库回传
            OrderToErpBO bean = (OrderToErpBO) obj;
            String type = String.valueOf(bean.getBillTypeId());
            map.put("type",type);
            map.put("return",msg);
        }else if ((BaseUrl+"/api/QCBill/PushQCBill").equals(url)){//质检回传
            map.put("type","999");
            map.put("return",msg);
        }else if ((BaseUrl+"/api/IMBill/CreateIMBill").equals(url)){//手动创建单据回传
            map.put("type","998");
            map.put("return",msg);
        }else if ((BaseUrl+"/api/Bill/CheckBill").equals(url)){//审核回传
            map.put("type","997");
            map.put("return",msg);
        } else if ((BaseUrl + "/api/Epichust/GetPOReceiving").equals(url)) {
            map.put("type","996");
            map.put("return",msg);
        }
        return map;
    }
    /**
     * 解析回传字段
     *
     * @param is
     * @return
     * @throws IOException
     */
    public static String inputStream2String(InputStream is) throws IOException {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        String result = "";
        try {
            int len = 0;
            byte[] date = new byte[4];
            while ((len = is.read(date)) != -1) {
                //将每一次的数据写入缓冲区
                outputStream.write(date, 0, len);
            }
            byte[] bytes = outputStream.toByteArray();
            result = new String(bytes, "utf-8");
            is.close();
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;

    }

    final static String ERP_TOKEN = "erp_access_token";//正式
//    final static String ERP_TOKEN = "erp_access_token_test";//测试

    @Override
    public String getToken() {

        String erpToken = (String) redisUtil.get(ERP_TOKEN);

        if (ObjectUtil.isEmpty(erpToken)) {
            //请求token
            MultiValueMap<String, String> stringMultiValueMap = new LinkedMultiValueMap<>();
//            stringMultiValueMap.add("client_id", "KingdeeK3_ApiClient_Rggytest"); //测试
//            stringMultiValueMap.add("client_secret", "TekE%dAISMCvwk7V"); //
//            String tokenUrl = "https://61.177.200.186:44310/connect/token"; //内网地址


            stringMultiValueMap.add("client_id", this.clientID);
            stringMultiValueMap.add("client_secret", this.ClientSecret);
            stringMultiValueMap.add("grant_type", "password");
            stringMultiValueMap.add("username", "epichust");
            stringMultiValueMap.add("password", "hK@vmz0YI1e^thtB");
            String tokenUrl = this.tokenUrl+ "/connect/token";
            String clientRg = null;
            try {
                clientRg = HttpClient.clientRg(tokenUrl, HttpMethod.POST, stringMultiValueMap);
            } catch (Exception e) {
                e.printStackTrace();
            }
            JSONObject jsonObject = JSONObject.parseObject(clientRg);
            erpToken = jsonObject.getString("access_token");
            //过期时间
            String pasts = jsonObject.getString("expires_in");
            redisUtil.set(ERP_TOKEN, erpToken, Long.valueOf(pasts));
        }
        return erpToken;
    }


    public String restFull(String url) {

        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.add("Accept", "application/json");
        httpHeaders.add("Authorization", "Bearer " + getToken());
        String result = null;

        try {
            return HttpClient.getRequest(url, null, httpHeaders);
        } catch (Exception e) {
            redisUtil.remove(ERP_TOKEN);
            e.printStackTrace();
        }
        return null;

    }


}
